package org.clockworkmages.games.anno1186;

import java.util.Map.Entry;

import org.clockworkmages.games.anno1186.model.character.GameCharacter;
import org.clockworkmages.games.anno1186.model.character.StatConstants;
import org.clockworkmages.games.anno1186.util.RollUtil;

public class CombatUtil {
	private CombatUtil() {

	}

	public static void performAttack(GameGuiService gameGuiService,
			GameCharacter defender, GameCharacter attacker) {
		double attackersAccuracy = attacker.getDerivates().get(
				StatConstants.D_ACCURACY);
		double defendersEvasion = defender.getDerivates().get(
				StatConstants.D_EVASION);

		// if my accuracy equals enemy's evasion then the chance to hit is 50%:
		double pow = attackersAccuracy - defendersEvasion;
		boolean hitSuccesfull = RollUtil.rollBase50(pow);

		String infoText;
		if (hitSuccesfull) {
			double totalUnresistedDamage = 0;// damage as it would be if the
												// enemy had no resistances
			double totalInflictedDamage = 0; // damage that was actually
												// inflicted, enemy's
												// resistances
												// considered
			for (Entry<String, Double> entry : attacker.getDamageMinimals()
					.entrySet()) {
				String damageType = entry.getKey();

				double damageMinimal = entry.getValue();
				Double damageRange = attacker.getDamageRanges().get(damageType);
				if (damageRange == null) {
					damageRange = 0d;
				}
				double unresistedDamage = damageMinimal + Math.random()
						* damageRange;

				if (DamageConstants.PHYSICAL.equals(damageType)) {
					// physical damage additionally gets modified with attackers
					// strength:
					unresistedDamage = unresistedDamage
							* (100d + attacker.getEffectiveStats().get(
									StatConstants.STRENGTH)) / 100d;
				}

				Double enemyResistance = defender.getDamageResistances().get(
						damageType);
				if (enemyResistance == null) {
					enemyResistance = 0d;
				}

				double inflictedDamage;
				if (enemyResistance == DamageConstants.IMMUNE) {
					// the enemy is completely resistant to that kind of damage
					inflictedDamage = 0d;
					continue;
				} else {
					inflictedDamage = unresistedDamage
							* Math.pow(0.99, enemyResistance);
				}
				totalUnresistedDamage += unresistedDamage;
				totalInflictedDamage += inflictedDamage;
			}

			if (totalInflictedDamage != 0) {
				defender.increaseBaseStat(StatConstants.HEALTH,
						-totalInflictedDamage);
				defender.setStatsAreStale(true);
			}

			infoText = (attacker.isEnemy() ? attacker.getName() + " hits you"
					: "You hit " + defender.getName())
					+ " for "
					+ (int) totalInflictedDamage
					+ " damage!"
					+ (totalInflictedDamage < totalUnresistedDamage ? " ("
							+ (int) (100 * totalInflictedDamage / totalUnresistedDamage)
							+ "% resisted)"
							: "");
		} else {
			infoText = attacker.isEnemy() //
			? (attacker.isAddThe() ? "The " : "") + attacker.getName()
					+ " misses!" //
					: "You miss!";
		}
		gameGuiService.getTextPane().addInfoToBuffer(infoText + "\n");
	}
}
